[IA64] Fix soft lock up caused by xen_timer_interrupt()
authorAlex Williamson <alex.williamson@hp.com>
Thu, 5 Jul 2007 19:04:00 +0000 (13:04 -0600)
committerAlex Williamson <alex.williamson@hp.com>
Thu, 5 Jul 2007 19:04:00 +0000 (13:04 -0600)
This patch intends to fix softlockup caused by xen_timer_interrupt().
This is caused by local_cpu_data->itm_next and stime_irq, itc_at_irq
inconsistency at CPU0 of hypervisor.  This patch sets stime_irq and
itc_at_irq every time in xen_timer_interrupt() to avoid this soft
lock up.

In other words, it is caused by competition of local_cpu_data->itm_next
and domain_itm in xen_timer_interrupt() and reprogram_timer() (more
specific vcpu_set_next_timer()).

For example:
 1) reprogram_timer() runs and set local_cpu_data->itm_next and set
    domain_itm as next itm.
 2) xen_timer_interrupt() called but following condition is not satisfied:
    while(time_after(ia64_get_itc(), local_cpu_data->itm_next)
    This skips stime_irq and itc_at_irq setting.
 3) goto 1)
 4) sometimes local_cpu_data->itm_next is rollback because
    ns_to_cycle()/IA64 is representing almost 32bit.
    (This occured at reprogram_timer())
 5) It causes soft lock up.
 6) Hypervisor returns to work(not hang).

To reproduce this issue, I do following configuration.

 1) boot Xen with pcpu=4 and Dom0 with vcpu=4
 2) boot domU1 with vcpu with vcpu-pin 0-1
 3) boot domU2 with vcpu with vcpu-pin 0-1
 4) run yes > /dev/null  2 process on domU1
 5) run nothing on domU2(to check softlock up occured or not)
 6) run kernel compile with -j4 on Dom0 continuously
 7) wait 4 or 8 hours to occur softlockup.

Signed-off-by: Atsushi SAKAI <sakaia@jp.fujitsu.com>
xen/arch/ia64/xen/xentime.c

index 7a118de38460b4c3b2c2d628664581260770561c..2266eee835cfc388f9d360dafc106fd5b99f6f4d 100644 (file)
@@ -126,9 +126,7 @@ xen_timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
 
 
        new_itm = local_cpu_data->itm_next;
-       while (time_after(ia64_get_itc(), new_itm)) {
-               new_itm += local_cpu_data->itm_delta;
-
+       while (1) {
                if (smp_processor_id() == TIME_KEEPER_ID) {
                        /*
                         * Here we are in the timer irq handler. We have irqs locally
@@ -150,6 +148,10 @@ xen_timer_interrupt (int irq, void *dev_id, struct pt_regs *regs)
 
                local_cpu_data->itm_next = new_itm;
 
+               if (time_after(new_itm, ia64_get_itc())) 
+                       break;
+
+               new_itm += local_cpu_data->itm_delta;
        }
 
        if (!is_idle_domain(current->domain) && !VMX_DOMAIN(current)) {